package main

import (
	"Ghost/mss"
	"Ghost/ntc"
	"Ghost/ntk"
	. "Ghost/utd"
	"Ghosted/pack"
	"Ghosted/util"
	//com "GhostedBin/Common"
	"errors"
	"fmt"
	"time"
)

type RobotClient struct {
	ntk.TcpConnect

	state mss.GoState

	// Login逻辑
	accntId util.TAccntId
	tokenId util.TTokenId
	toGate  *pack.SNetNode
	// Lobby逻辑

	// Scene逻辑

	// 公共逻辑
	roleId util.TRoleId

	// 控制节奏
	connectTime    time.Time
	overTime       time.Duration
	lastChatTime   time.Time
	lastSwitchTime time.Time
}

func (this *RobotClient) HandleInit(own mss.IOServicer) {
	this.TcpConnect.HandleInit(own)

	this.lastSwitchTime = time.Now()
	this.overTime = TDurt(5+Ucom.RandInt(5)) * time.Second

	this.state.AddFun(int(ERS_Login), this.onTikStateLogic)
	this.state.AddFun(int(ERS_Lobby), this.onTikStateLobby)
	this.state.AddFun(int(ERS_Scene), this.onTikStateScene)

	this.SetRunState(ERS_Login)

	this.TimerHandler(util.DEF_CLIENT_PING_GAP_TIME, this.onTimPingMessage)

	this.SetReConnInterval(DEF_CLIENT_RECONN_TIME)

	this.SetMsgHandler(pack.MT_PING, this.OnMsgPing)
	this.SetMsgHandler(pack.MT_SWITCH_GATE, this.OnMsgSwitchGate)
	this.SetMsgHandler(pack.MT_LOGOUT_A, this.OnMsgLogoutA)
	this.SetMsgHandler(pack.MT_EXIT, this.OnMsgExit)
	this.SetMsgHandler(ntc.DEF_DEFAULT_MSGTYPE, this.OnMsgDefaultMessage)
}
func (this *RobotClient) HandleTick(now time.Time) {
	this.TcpConnect.HandleTick(now)

	this.state.Run()
}
func (this *RobotClient) HandleTerm(reason error) {
	this.TcpConnect.HandleTerm(reason)
	theMCMain.RecoverRobot(this.SieId())
}

func (this *RobotClient) HandleConnected(reconn bool) {
	this.TcpConnect.HandleConnected(reconn)
}
func (this *RobotClient) HandleDisConnect(reason error) {
	this.TcpConnect.HandleDisConnect(reason)
}

//------------------------------------------------------------------------------
//===================================Logical====================================
//------------------------------------------------------------------------------
func (this *RobotClient) SetRunState(s ERobotState) { this.state.Set(int(s)); this.Debug("%q", s) }

func (this *RobotClient) destroy(reason error) {
	this.Warn("reason:%q", reason.Error())
	this.Stop(reason, false) // 自行退出
}

// -------- Timer Handler
func (this *RobotClient) onTikStateLogic(enter bool) {
	if enter {
		host := LoginHost[Ucom.RandInt(len(LoginHost))]
		if err := this.TcpConnect.StartConnecT(host, time.Second*2, DEF_CLIENT_CHAN_SIZE); err != nil {
			this.destroy(err)
			return
		}

		msg := pack.MakeMsgLoginQ()
		msg.AuthMode = 1
		msg.Account = fmt.Sprintf("%s%05d", DEF_ACCOUNT_PREFIX, this.SieId())
		this.Debug("account:%v", msg.Account)
		msg.Password = DEF_ACCOUNT_PASSWORD

		this.SentReqHandle(msg, this, func(mReq, mAck ntc.IMsger) {
			if ntc.IsErrRetAck(mAck) {
				this.destroy(errors.New(mAck.(*ntc.MsgErrRet).Erring()))
				return
			}

			ack := mAck.(*pack.MsgLoginA)
			this.accntId = util.TAccntId(ack.AccntId)
			this.tokenId = util.TTokenId(ack.TokenId)
			this.toGate = ack.NetGate
			this.TcpConnect.CloseConnect()

			this.SetRunState(ERS_Lobby)
		})
	}
}
func (this *RobotClient) onTikStateLobby(enter bool) {
	if enter {
		host := fmt.Sprintf("%s", this.toGate.ListnTAddr)
		if err := this.TcpConnect.StartCOnnect(host, time.Second*3, DEF_CLIENT_CHAN_SIZE, true, true, false); err != nil {
			this.destroy(err)
			return
		}
		msg := pack.MakeMsgAllocRoleQ()
		msg.AccntId, msg.TokenId = this.accntId, uint64(this.tokenId)
		this.SentReqHandle(msg, this, func(mReq, mAck ntc.IMsger) {
			if ntc.IsErrRetAck(mAck) {
				this.destroy(errors.New(mAck.(*ntc.MsgErrRet).Erring()))
				return
			}

			ack := mAck.(*pack.MsgAllocRoleA)
			this.roleId = util.TRoleId(ack.RoleId)
			this.Debug("Alloc RoleId:%d", this.roleId)
			this.SetRunState(ERS_Lobby)
		})
		return
	}

	if this.state.Been() > 10*time.Second {
		this.SendSignOut()
	}
}
func (this *RobotClient) onTikStateScene(enter bool) {
}
func (this *RobotClient) onTimPingMessage(now time.Time) bool {
	msg := pack.MakeMsgPing()
	msg.Time = time.Now().UnixNano()
	this.SendMessage(msg)
	return true
}

// -------- Send Message
func (this *RobotClient) SendReconnectQ() {
	msg := pack.MakeMsgReconnectQ()
	msg.AccntId, msg.TokenId = this.accntId, uint64(this.tokenId)
	this.SendMessage(msg)
}
func (this *RobotClient) SendSignOut() {
	msg := pack.MakeMsgLogoutQ()
	msg.Value = 10
	this.SentRequest(msg)
}

// -------- Msg Handler
func (this *RobotClient) OnMsgPing(mReq, mAck ntc.IMsger) {
	this.Trace("Ping to server delay:%v", time.Since(time.Unix(0, mAck.(*pack.MsgPing).Time)))
}
func (this *RobotClient) OnMsgLogoutA(mReq, mAck ntc.IMsger) {

}
func (this *RobotClient) OnMsgSwitchGate(mReq, mAck ntc.IMsger) {
	swit := mAck.(*pack.MsgSwitchGate)
	this.TcpConnect.CloseConnect()
	this.Debug("收到切换消息 swit:%v", swit)
	err := this.TcpConnect.StartConnecT(swit.ToGateTAddr, time.Second*3, DEF_CLIENT_CHAN_SIZE)
	if err != nil {
		this.destroy(errors.New(fmt.Sprintf("StartConnect to Gate error:%v", err)))
		return
	}
}
func (this *RobotClient) OnMsgExit(mReq, mAck ntc.IMsger) {
	exit := mAck.(*pack.MsgExit)
	this.Debug("Exit:{type:%v info:%s}", exit.ExitType, exit.ExitInfo)
	this.destroy(mss.ErrNormalExit)
}
func (this *RobotClient) OnMsgDefaultMessage(mReq, mAck ntc.IMsger) {
	this.Debug("unknow msg:%s", ntc.MessageName(mAck))
}
